//
//  main.cpp
//  
//
//  Created by Kun Zhao on 12/12/05.
//  Copyright (c) 2012 Kyoto University. All rights reserved.
//

#include <iostream>
#include <kvs/glut/Application>
#include <kvs/glut/Screen>
#include <kvs/StructuredVolumeObject>
#include <kvs/StructuredVolumeImporter>
#include <kvs/CommandLine>
#include "RayCastingRenderer.h"
#include "TransferFunction3D.h"
#include "CreateString.h"

kvs::glut::Timer* glut_timer;
kun::TransferFunction3D tfunc3d;
std::string tfunc_filename;
size_t time_step;
size_t nsteps;
kvs::StructuredVolumeObject** volume_s;
kvs::StructuredVolumeObject** volume_t;
kvs::StructuredVolumeObject** volume_v;

class Argument : public kvs::CommandLine
{
public:
     
    std::string year;
    
    Argument( int argc, char** argv ) : CommandLine( argc, argv )
    {
        add_help_option();
        addOption( "y", "year of the data", 1, true );
        addOption( "t", "3D transfer function", 1, true );
    }
    
    void exec()
    {
        if( !this->parse() ) exit( EXIT_FAILURE );
        if( this->hasOption( "y" ) ) year = this->optionValue<std::string>( "y" );
        if( this->hasOption( "t" ) ) tfunc_filename = this->optionValue<std::string>(  "t" );
    }
    
};

class TimerEvent : public kvs::TimerEventListener
{
    void update( kvs::TimeEvent* event )
    {
        kun::RayCastingRenderer* renderer = new kun::RayCastingRenderer();
        renderer->setName( "renderer" );
        renderer->addVolume2( volume_t[time_step] );
        renderer->addVolume3( volume_v[time_step] );
        renderer->set3DTransferFunction( tfunc3d );
        
        screen()->objectManager()->change( "object", volume_s[time_step++], false );
        screen()->rendererManager()->change( "renderer", renderer, true );
        std::cout << "time step: " << time_step <<std::flush;
        screen()->redraw();
        if( time_step == nsteps ) 
        {
            time_step = 0;
            glut_timer->stop();
        }
    }
};

class KeyPressEvent : public kvs::KeyPressEventListener
{
    void update( kvs::KeyEvent* event )
    {
        switch ( event->key() )
        {
            case kvs::Key::s:
            {
                if ( glut_timer-> isStopped() )
                {
                    glut_timer->start();
                    screen()->redraw();
                }
                else
                {
                    glut_timer->stop();
                    screen()->redraw();
                }
                break;
                
            }
	  case kvs::Key::t:
	  {
	    tfunc3d.import( tfunc_filename );
	    break;
	  }
        }
    }
};

int main( int argc, char** argv )
{
    kvs::glut::Application app( argc, argv );
    kvs::glut::Screen screen( &app );
    
    Argument param( argc, argv );
    param.exec();
    
    size_t ndays = 8;
    nsteps = 8 * ndays;
    volume_s = new kvs::StructuredVolumeObject*[nsteps];
    volume_t = new kvs::StructuredVolumeObject*[nsteps];
    volume_v = new kvs::StructuredVolumeObject*[nsteps];

    std::string base = "../../../Data/Ocean/" + param.year + "/" + param.year + "040";
    
    for ( size_t j = 1; j <= ndays; j++ )
    {
        char buf[10];
        sprintf( buf, "%d", j );
        std::string directory = base + std::string(buf) + "/";
        for ( size_t i = 0; i < 8; i++ )
        {
            size_t step = i + ( j - 1 ) * 8;
            volume_s[step] = new kvs::StructuredVolumeImporter( CreateString( directory +  "s_0", i, "kvsml" ) );
            volume_t[step] = new kvs::StructuredVolumeImporter( CreateString( directory + "rhoo_0", i, "kvsml" ) );
            volume_v[step] = new kvs::StructuredVolumeImporter( CreateString( directory + "velocity_0", i, "kvsml" ) );
            volume_s[step]->setName( "object" );
            std::cout << "finish loading time step: " << step << std::endl;
        }
    }

    tfunc3d.import( tfunc_filename );
    time_step = 0;
    
    KeyPressEvent key_press_event;
    TimerEvent timer_event;
    glut_timer = new kvs::glut::Timer( 50 );
    
    kun::RayCastingRenderer* renderer = new kun::RayCastingRenderer();
    
    renderer->setName( "renderer" );
    renderer->addVolume2( volume_t[0] );
    renderer->addVolume3( volume_v[0] );
    renderer->set3DTransferFunction( tfunc3d );
                                                                                     
    screen.addKeyPressEvent( &key_press_event );
    screen.addTimerEvent( &timer_event, glut_timer );
    screen.registerObject( volume_s[0], renderer );
    screen.setTitle( "Animation Rendering" );
    screen.show();
    
    glut_timer->start( 50 );
    glut_timer->stop();
    
    return( app.run() );   
}
